package IntelIpps

/*
#cgo CFLAGS: -ID:/DevelopTools/IPPS2022/ipp/2021.12/include
#cgo LDFLAGS: -LD:/DevelopTools/IPPS2022/ipp/2021.12/lib -lipps -lippcore
#include <ipp.h>
#include <stdlib.h>
*/
import "C"
import "unsafe"

type medianState struct {
	buffer   []byte
	dlySrc   []float32
	dlyDst   []float32
	maskSize int
}

var medianGlobal *medianState

func (i *IppImpl) FilterMedian(src []float32, maskSize int) []float32 {
	if len(src) == 0 || maskSize <= 0 || maskSize%2 == 0 {
		return src
	}

	// 重新初始化
	if medianGlobal == nil || medianGlobal.maskSize != maskSize {
		i.initMedian(maskSize)
	}

	dst := make([]float32, len(src))
	status := C.ippsFilterMedian_32f(
		(*C.Ipp32f)(unsafe.Pointer(&src[0])),
		(*C.Ipp32f)(unsafe.Pointer(&dst[0])),
		C.int(len(src)),
		C.int(maskSize),
		(*C.Ipp32f)(unsafe.Pointer(&medianGlobal.dlySrc[0])),
		(*C.Ipp32f)(unsafe.Pointer(&medianGlobal.dlyDst[0])),
		(*C.Ipp8u)(unsafe.Pointer(&medianGlobal.buffer[0])),
	)
	if status != C.ippStsNoErr {
		return src
	}
	return dst
}

func (i *IppImpl) initMedian(maskSize int) {
	var bufferSize C.int
	C.ippsFilterMedianGetBufferSize(C.int(maskSize), C.ipp32f, &bufferSize)

	buffer := make([]byte, bufferSize)
	dlySrc := make([]float32, maskSize-1)
	dlyDst := make([]float32, maskSize-1)

	medianGlobal = &medianState{
		buffer:   buffer,
		dlySrc:   dlySrc,
		dlyDst:   dlyDst,
		maskSize: maskSize,
	}
}

// Threshold
func (i *IppImpl) Threshold(src []float32, level, value float32) []float32 {
	dst := make([]float32, len(src))
	copy(dst, src)
	C.ippsThreshold_LTAbsVal_32f(
		(*C.Ipp32f)(unsafe.Pointer(&dst[0])),
		(*C.Ipp32f)(unsafe.Pointer(&dst[0])),
		C.int(len(src)),
		C.Ipp32f(level),
		C.Ipp32f(value),
	)
	return dst
}

// CartToPolar
func (i *IppImpl) CartToPolar(x, y []float32) (magn, phase []float32) {
	if len(x) != len(y) {
		return nil, nil
	}
	magn = make([]float32, len(x))
	phase = make([]float32, len(x))
	C.ippsCartToPolar_32f(
		(*C.Ipp32f)(unsafe.Pointer(&x[0])),
		(*C.Ipp32f)(unsafe.Pointer(&y[0])),
		(*C.Ipp32f)(unsafe.Pointer(&magn[0])),
		(*C.Ipp32f)(unsafe.Pointer(&phase[0])),
		C.int(len(x)),
	)
	return magn, phase
}

// Flip
func (i *IppImpl) Flip(src []float32) []float32 {
	dst := make([]float32, len(src))
	C.ippsFlip_32f(
		(*C.Ipp32f)(unsafe.Pointer(&src[0])),
		(*C.Ipp32f)(unsafe.Pointer(&dst[0])),
		C.int(len(src)),
	)
	return dst
}
